import java.util.concurrent.PriorityBlockingQueue;

/**
 * Creat with IntelliJ IDEA
 * Description:
 * User:WZW
 * Date:2022-09-21
 * Time:14:35
 */
public class MyTimer {

    private Object mailBox = new Object();

    // 通过队列在组织Task对象
    private PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();

    // 通过schedule往队列中添加Task对象
    public void schedule(Runnable command, long after) {
        Task task = new Task(command,after);
        queue.offer(task);

        // 当添加新任务的时候，都唤醒一下worker线程。（因为新插入的任务可能是需要马上执行的）
        synchronized (mailBox) {
            mailBox.notify();
        }
    }

    public MyTimer() {
        Worker worker = new Worker();
        worker.start();
    }

    //worker线程，用于不停扫描队首元素，看看是否能执行这个任务
    class Worker extends Thread{
        @Override
        public void run() {
            while (true) {
                try {
                    Task task = queue.take();
                    long curTime = System.currentTimeMillis();
                    if (task.time > curTime) {
                        // 时间未到，把任务放回队列中
                        queue.put(task);

                        // 不再忙等，而使用wait
                        synchronized (mailBox) {
                            // 指定等待时间 wait
                            mailBox.wait(task.time - curTime);
                        }
                    } else {
                        // 时间到了，执行任务
                        task.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }

    // Task类用于描述一个任务，包含一个Runnable对象和一个time（毫秒时间戳）
    static class Task implements Comparable<Task> {
        private Runnable command;
        private long time;

        public Task(Runnable command, long time) {
            this.command = command;
            this.time = System.currentTimeMillis() + time;
        }

        public void run() {
            command.run();
        }

        @Override
        public int compareTo(Task o) {
            //时间小的排在前面
            return (int)(time - o.time);
        }

    }
}
